package timber.log

import com.gitee.wsl.logger.LogLevel
import com.gitee.wsl.logger.Logger

/** Logging for lazy people. */
object Timber : Tree() {
}

/** A facade for handling logging calls. Install instances via [`Timber.plant()`][.plant]. */
 abstract class Tree {

    internal open var tag: String? = null

    fun tag(newTag:String):Tree{
        tag = newTag
        return this
    }

    /** Log a verbose message with optional format args. */
    open fun v(message: String?, vararg args: Any?) {
        prepareLog(LogLevel.VERBOSE, null, message, *args)
    }

    /** Log a verbose exception and a message with optional format args. */
    open fun v(t: Throwable?, message: String?, vararg args: Any?) {
        prepareLog(LogLevel.VERBOSE, t, message, *args)
    }

    /** Log a verbose exception. */
    open fun v(t: Throwable?) {
        prepareLog(LogLevel.VERBOSE, t, null)
    }

    /** Log a debug message with optional format args. */
    open fun d(tag: String?,message: String?, vararg args: Any?) {
        prepareLog(LogLevel.DEBUG, null, message, *args)
    }

    /** Log a debug message with optional format args. */
    open fun d(message: String?, vararg args: Any?) {
        prepareLog(LogLevel.DEBUG, null, message, *args)
    }

    /** Log a debug exception and a message with optional format args. */
    open fun d(t: Throwable?, message: String?, vararg args: Any?) {
        prepareLog(LogLevel.DEBUG, t, message, *args)
    }

    /** Log a debug exception. */
    open fun d(t: Throwable?) {
        prepareLog(LogLevel.DEBUG, t, null)
    }

    /** Log an info message with optional format args. */
    open fun i(message: String?, vararg args: Any?) {
        prepareLog(LogLevel.INFO, null, message, *args)
    }

    /** Log an info exception and a message with optional format args. */
    open fun i(t: Throwable?, message: String?, vararg args: Any?) {
        prepareLog(LogLevel.INFO, t, message, *args)
    }

    /** Log an info exception. */
    open fun i(t: Throwable?) {
        prepareLog(LogLevel.INFO, t, null)
    }

    /** Log a warning message with optional format args. */
    open fun w(message: String?, vararg args: Any?) {
        prepareLog(LogLevel.WARNING, null, message, *args)
    }

    /** Log a warning exception and a message with optional format args. */
    open fun w(t: Throwable?, message: String?, vararg args: Any?) {
        prepareLog(LogLevel.WARNING, t, message, *args)
    }

    /** Log a warning exception. */
    open fun w(t: Throwable?) {
        prepareLog(LogLevel.WARNING, t, null)
    }

    /** Log an error message with optional format args. */
    open fun e(message: String?, vararg args: Any?) {
        prepareLog(LogLevel.ERROR, null, message, *args)
    }

    /** Log an error exception and a message with optional format args. */
    open fun e(t: Throwable?, message: String?, vararg args: Any?) {
        prepareLog(LogLevel.ERROR, t, message, *args)
    }

    /** Log an error exception. */
    open fun e(t: Throwable?) {
        prepareLog(LogLevel.ERROR, t, null)
    }

    /** Log an assert message with optional format args. */
    open fun wtf(message: String?, vararg args: Any?) {
        prepareLog(LogLevel.WTF, null, message, *args)
    }

    /** Log an assert exception and a message with optional format args. */
    open fun wtf(t: Throwable?, message: String?, vararg args: Any?) {
        prepareLog(LogLevel.WTF, t, message, *args)
    }

    /** Log an assert exception. */
    open fun wtf(t: Throwable?) {
        prepareLog(LogLevel.WTF, t, null)
    }

    /** Log at `priority` a message with optional format args. */
    open fun log(priority: LogLevel, message: String?, vararg args: Any?) {
        prepareLog(priority, null, message, *args)
    }

    /** Log at `priority` an exception and a message with optional format args. */
    open fun log(priority: LogLevel, t: Throwable?, message: String?, vararg args: Any?) {
        prepareLog(priority, t, message, *args)
    }

    /** Log at `priority` an exception. */
    open fun log(priority: LogLevel, t: Throwable?) {
        prepareLog(priority, t, null)
    }

    /** Return whether a message at `priority` should be logged. */
    @Deprecated("Use isLoggable(String, int)", ReplaceWith("this.isLoggable(null, priority)"))
    protected open fun isLoggable(priority: LogLevel) = true

    /** Return whether a message at `priority` or `tag` should be logged. */
    protected open fun isLoggable(tag: String?, priority: LogLevel) = isLoggable(priority)

    private fun prepareLog(priority: LogLevel, t: Throwable?, message: String?, vararg args: Any?) {
        // Consume tag even when message is not loggable so that next message is correctly tagged.
        val tag = tag
        if (!isLoggable(tag, priority)) {
            return
        }

        var message = message
        if (message.isNullOrEmpty()) {
            if (t == null) {
                return  // Swallow message if it's null and there's no throwable.
            }
            message = t.stackTraceToString()
        } else {
            if (args.isNotEmpty()) {
                message = formatMessage(message, args)
            }
            if (t != null) {
                message += "\n" + t.stackTraceToString()
            }
        }

        /*if (tag != null) {
            Logger[tag].log(priority,  message, t)
        }else{
            Logger.log(priority,  message, t)
        }*/
        Logger.log(priority,  message, t)
    }

    /** Formats a log message with optional arguments. */
    protected open fun formatMessage(message: String, args: Array<out Any?>) = message

    //private fun getStackTraceString(t: Throwable) = t.stackTraceToString()

    /**
     * Write a log message to its destination. Called for all level-specific methods by default.
     *
     * @param priority Log level. See [Log] for constants.
     * @param tag Explicit or inferred tag. May be `null`.
     * @param message Formatted log message.
     * @param t Accompanying exceptions. May be `null`.
     */
     fun log(priority: LogLevel, tag: String?, message: String, t: Throwable?){
         this.tag=tag
         prepareLog(priority,t,message)
    }
}

fun Tree.d(block:()->String) = d(block())

fun Tree.v(block:()->String) = v(block())

fun Tree.e(block:()->String) = e(block())

fun Tree.i(block:()->String) = i(block())